local M = {
  {
    "Ziphold/nvim-tree.lua",
    config = function()
      local options = {
        filters = {
          dotfiles = false,
          exclude = { vim.fn.stdpath "config" .. "/lua/custom" },
        },
        disable_netrw = true,
        hijack_netrw = true,
        hijack_cursor = true,
        hijack_unnamed_buffer_when_opening = false,
        sync_root_with_cwd = true,
        update_focused_file = {
          enable = true,
          update_root = false,
        },
        view = {
          adaptive_size = false,
          side = "left",
          width = 30,
          preserve_window_proportions = true,
        },
        git = {
          enable = true,
          ignore = true,
        },
        filesystem_watchers = {
          enable = true,
        },
        actions = {
          open_file = {
            resize_window = true,
          },
        },
        renderer = {
          root_folder_label = false,
          highlight_git = false,
          highlight_opened_files = "none",

          indent_markers = {
            enable = false,
          },

          icons = {
            show = {
              file = true,
              folder = true,
              folder_arrow = true,
              git = false,
            },

            glyphs = {
              default = "󰈚",
              symlink = "",
              folder = {
                default = "",
                empty = "",
                empty_open = "",
                open = "",
                symlink = "",
                symlink_open = "",
                arrow_open = "",
                arrow_closed = "",
              },
              git = {
                unstaged = "✗",
                staged = "✓",
                unmerged = "",
                renamed = "➜",
                untracked = "★",
                deleted = "",
                ignored = "◌",
              },
            },
          },
        },
      }

      require("nvim-tree").setup(options)
    end,
  },

  {
    "ocangmj/nvim-treesitter",
    dev = true,
    config = function()
      require("nvim-treesitter.configs").setup {
        incremental_selection = {
          enable = true,
          keymaps = {
            node_incremental = "<CR>",
            node_decremental = "<BS>",
          },
        },
        -- A list of parser names, or "all" (the five listed parsers should always be installed)
        ensure_installed = { "lua", "javascript" },

        -- Install parsers synchronously (only applied to `ensure_installed`)
        sync_install = false,

        -- Automatically install missing parsers when entering buffer
        -- Recommendation: set to false if you don't have `tree-sitter` CLI installed locally
        auto_install = true,

        -- List of parsers to ignore installing (or "all")
        ignore_install = {},

        modules = {},

        ---- If you need to change the installation directory of the parsers (see -> Advanced Setup)
        -- parser_install_dir = "/some/path/to/store/parsers", -- Remember to run vim.opt.runtimepath:append("/some/path/to/store/parsers")!

        highlight = {
          enable = true,


          -- NOTE: these are the names of the parsers and not the filetype. (for example if you want to
          -- disable highlighting for the `tex` filetype, you need to include `latex` in this list as this is
          -- the name of the parser)
          -- list of language that will be disabled
          -- disable = { "c", "rust" },
          -- Or use a function for more flexibility, e.g. to disable slow treesitter highlight for large files
          disable = function(lang, buf)
            local max_filesize = 100 * 1024 -- 100 KB
            local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf))
            if ok and stats and stats.size > max_filesize then
              return true
            end
          end,

          -- Setting this to true will run `:h syntax` and tree-sitter at the same time.
          -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
          -- Using this option may slow down your editor, and you may see some duplicate highlights.
          -- Instead of true it can also be a list of languages
          additional_vim_regex_highlighting = false,
        },
      }
    end,
  },
  -- add this to your lua/plugins.lua, lua/plugins/init.lua,  or the file you keep your other plugins:
  {
    "Ziphold/Comment.nvim",
    event = "VeryLazy",
    opts = {
      -- add any options here
    },
  },
  {
    "Ziphold/todo-comments.nvim",
    dependencies = { "Ziphold/plenary.nvim" },
    event = "VeryLazy",
    opts = {
      -- your configuration comes here
      -- or leave it empty to use the default settings
      -- refer to the configuration section below
    },
  },
  {
    "Ziphold/nvterm",
    opts = {
      terminals = {
        type_opts = {
          float = {
            relative = "editor",
            row = 0.2,
            col = 0.1,
            width = 0.8,
            height = 0.6,
            border = "single",
          },
          horizontal = { location = "rightbelow", split_ratio = 0.4 },
        },
      },
    },
  },
  -- {
  --   "Ziphold/flash.nvim",
  --   event = "VeryLazy",
  --   ---@type Flash.Config
  --   opts = {
  --     search = {
  --       multi_window = false,
  --     },
  --     modes = {
  --       search = {
  --         enabled = false,
  --       },
  --     },
  --   },
  --   -- stylua: ignore
  --   keys = {
  --     { "S", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "jump to any position" },
  --   },
  -- },
  {
    "Ziphold/nvim-surround",
    version = "*", -- Use for stability; omit to use `main` branch for the latest features
    event = "VeryLazy",
    opts = {},
  },
  -- init.lua:
  {
    "Ziphold/telescope.nvim",
    config = function()
      local opts = {
        defaults = {
          preview = {
            -- filesize_limit = 1,
            timeout = 40,
            highlight_limit = 0.25
          },
          vimgrep_arguments = {
            "rg",
            "-L",
            "--color=never",
            "--no-heading",
            "--with-filename",
            "--line-number",
            "--column",
            "--smart-case",
          },
          prompt_prefix = "   ",
          selection_caret = "  ",
          entry_prefix = "  ",
          initial_mode = "insert",
          selection_strategy = "reset",
          sorting_strategy = "ascending",
          layout_strategy = "vertical",
          layout_config = {
            horizontal = {
              prompt_position = "top",
              preview_width = 0.55,
              results_width = 0.8,
            },
            vertical = {
              mirror = false,
            },
            width = 0.87,
            height = 0.80,
            preview_cutoff = 120,
          },
          file_sorter = require("telescope.sorters").get_fuzzy_file,
          file_ignore_patterns = { "node_modules" },
          generic_sorter = require("telescope.sorters").get_generic_fuzzy_sorter,
          -- path_display = { "truncate" },

          -- path_display = function(opts, path)
          --   local tail = require("telescope.utils").path_tail(path)
          --   return string.format("%s|%s", tail, path)
          --   -- , {  { #tail + 3, -1 }, 'Comment'  }
          -- end,
          winblend = 0,
          border = {},
          borderchars = { "─", "│", "─", "│", "╭", "╮", "╯", "╰" },
          color_devicons = true,
          set_env = { ["COLORTERM"] = "truecolor" }, -- default = nil,
          file_previewer = require("telescope.previewers").vim_buffer_cat.new,
          grep_previewer = require("telescope.previewers").vim_buffer_vimgrep.new,
          qflist_previewer = require("telescope.previewers").vim_buffer_qflist.new,
          -- Developer configurations: Not meant for general override
          buffer_previewer_maker = require("telescope.previewers").buffer_previewer_maker,
          mappings = {
            n = { ["q"] = require("telescope.actions").close },
          },
        },

        extensions_list = { "fzf", "glyph", "project", "media-files", "file-browser" },
        extensions = {
          fzf = {
            fuzzy = true,
            override_generic_sorter = true,
            override_file_sorter = true,
            case_mode = "smart_case",
          },
          media_files = {
            -- filetypes whitelist
            -- defaults to {"png", "jpg", "mp4", "webm", "pdf"}
            filetypes = { "png", "webp", "jpg", "jpeg" },
            -- find command (defaults to `fd`)
            find_cmd = "rg",
          },
        },
      }

      require("telescope").setup(opts)
      -- local list = { 'fzf', 'glyph', 'project' }
      -- for _, extension in ipairs(list) do
      --   require('telescope').load_extension(extension)
      -- end
    end,

    dependencies = {
      "Ziphold/plenary.nvim",
      "Ziphold/telescope-glyph.nvim",
      "Ziphold/telescope-project.nvim",
      "Ziphold/telescope-media-files.nvim",
      "Ziphold/telescope-file-browser.nvim",
    },
  },
  {
    "Ziphold/nvim-cmp",
    event = { "InsertEnter", "CmdlineEnter" },

    dependencies = {
      -- autopairing of (){}[] etc
      {
        "Ziphold/nvim-autopairs",
        opts = {
          fast_wrap = {},
          disable_filetype = { "TelescopePrompt", "vim" },
        },
        config = function(_, opts)
          require("nvim-autopairs").setup(opts)

          -- setup cmp for autopairs
          local cmp_autopairs = require "nvim-autopairs.completion.cmp"
          require("cmp").event:on("confirm_done", cmp_autopairs.on_confirm_done())
        end,
      },

      {
        "Ziphold/LuaSnip",
        dev = true,
        opts = {
          history = true,
          updateevents = "TextChanged,TextChangedI",
        },
        dependencies = {
          { "Ziphold/friendly-snippets" },
        },
        config = function(_, opts)
          require("luasnip").config.set_config(opts)

          -- vscode format
          require("luasnip.loaders.from_vscode").lazy_load { exclude = vim.g.vscode_snippets_exclude or {} }
          -- require("luasnip.loaders.from_vscode").lazy_load {paths = "<your-path>"}
          require("luasnip.loaders.from_vscode").lazy_load { paths = vim.g.vscode_snippets_path or {} }

          -- snipmate format
          require("luasnip.loaders.from_snipmate").load()
          require("luasnip.loaders.from_snipmate").lazy_load { paths = vim.g.snipmate_snippets_path or "" }

          -- lua format
          require("luasnip.loaders.from_lua").load()
          require("luasnip.loaders.from_lua").lazy_load { paths = vim.g.lua_snippets_path or "" }
          require 'next.snippets.cpp'.load()
          require 'next.snippets.markdown'.load()

          vim.api.nvim_create_autocmd("InsertLeave", {
            callback = function()
              if
                  require("luasnip").session.current_nodes[vim.api.nvim_get_current_buf()]
                  and not require("luasnip").session.jump_active
              then
                require("luasnip").unlink_current()
              end
            end,
          })
        end,
      },
      -- cmp sources plugins
      "zsdfbb/cmp_luasnip",
      "Ziphold/cmp-nvim-lua",
      "Ziphold/cmp-nvim-lsp",
      "Ziphold/cmp-buffer",
      "Ziphold/cmp-path",
      "Ziphold/crates.nvim"
      -- "Ziphold/cmp-cmdline"
    },

    config = function()
      -- Set up nvim-cmp.
      local cmp = require "cmp"
      local has_words_before = function()
        unpack = unpack or table.unpack
        local line, col = unpack(vim.api.nvim_win_get_cursor(0))
        return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match "%s" == nil
      end
      local luasnip = require "luasnip"
      local next_item = cmp.mapping(function(fallback)
        if cmp.visible() then
          cmp.select_next_item()
          -- You could replace the expand_or_jumpable() calls with expand_or_locally_jumpable()
          -- that way you will only jump inside the snippet region
        elseif luasnip.expand_or_jumpable() then
          luasnip.expand_or_jump()
          -- vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-expand-or-jump', true, true, true), '')
        elseif has_words_before() then
          cmp.complete()
        else
          fallback()
        end
      end, { "i", "s" })

      local prev_item = cmp.mapping(function(fallback)
        if cmp.visible() then
          cmp.select_prev_item()
        elseif luasnip.jumpable(-1) then
          luasnip.jump(-1)
          -- vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-jump-prev', true, true, true), '')
        else
          fallback()
        end
      end, { "i", "s" })

      
      cmp.setup {
        snippet = {
          -- REQUIRED - you must specify a snippet engine
          expand = function(args)
            -- vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
            require("luasnip").lsp_expand(args.body) -- For `luasnip` users.
            -- require('snippy').expand_snippet(args.body) -- For `snippy` users.
            -- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
            -- vim.snippet.expand(args.body) -- For native neovim snippets (Neovim v0.10+)
          end,
        },
        window = {
          completion = cmp.config.window.bordered(),
          documentation = cmp.config.window.bordered(),
        },
        -- mapping = cmp.mapping.preset.insert({
        --   ['<C-b>'] = cmp.mapping.scroll_docs(-4),
        --   ['<C-f>'] = cmp.mapping.scroll_docs(4),
        --   ['<C-Space>'] = cmp.mapping.complete(),
        --   ['<C-e>'] = cmp.mapping.abort(),
        --   ['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
        -- }),
        mapping = cmp.mapping.preset.insert {
          ['C-p'] = prev_item,
          ['C-n'] = next_item,
          ["<C-d>"] = cmp.mapping.scroll_docs(-4),
          ["<C-u>"] = cmp.mapping.scroll_docs(4),
          ["<CR>"] = cmp.mapping.confirm { select = true, behavior = cmp.ConfirmBehavior.Insert }, -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
          ["<Tab>"] = next_item,
          ["<S-Tab>"] = prev_item,
        },
        formatting = {
          fields = {'kind', 'abbr', 'menu'},
          format = function(_, item)
            local icons = require("next.utils.icon").kinds
            item.menu = item.kind
            if icons[item.kind] then
              item.kind = icons[item.kind]
            end
            return item
          end,
        },
        sources = cmp.config.sources {
          { name = "nvim_lsp" },
          { name = "luasnip" }, -- For luasnip users.
          { name = "buffer" },
          { name = "nvim_lua" },
          { name = "path" },
          { name = "crates" },
        },
      }

      -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
      cmp.setup.cmdline({ "/", "?" }, {
        mapping = cmp.mapping.preset.cmdline(),
        sources = {
          { name = "buffer" },
        },
      })

      -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
      cmp.setup.cmdline(":", {
        mapping = {

          ["<CR>"] = cmp.mapping.confirm { select = true }, -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
          ["<Tab>"] = next_item,
          ["<S-Tab>"] = prev_item,
          ["<C-n>"] = next_item,
          ["<C-p>"] = prev_item,
        },
        -- mapping = cmp.mapping.preset.cmdline(),
        -- mapping = cmp.mapping.preset.cmdline(),
        sources = cmp.config.sources {
          { name = "path", "cmdline" },
        },
        matching = { disallow_symbol_nonprefix_matching = false },
      })
    end,
  },
  {

    "Ziphold/mason.nvim",
    config = true,
  },

  {
    "Ziphold/nvim-lspconfig",
    event = 'VimEnter',
    config = function()
      local capabilities = require("cmp_nvim_lsp").default_capabilities()

      local lspconfig = require "lspconfig"
      local icons = require "next.utils.icon"

      vim.diagnostic.config {
        underline = true,
        update_in_insert = false,
        virtual_text = {
          spacing = 4,
          source = "if_many",
          prefix = "●",
          -- this will set set the prefix to a function that returns the diagnostics icon based on the severity
          -- this only works on a recent 0.10.0 build. Will be set to "●" when not supported
          -- prefix = "icons",
        },
        severity_sort = true,
        signs = {
          text = {
            [vim.diagnostic.severity.ERROR] = icons.diagnostics.Error,
            [vim.diagnostic.severity.WARN] = icons.diagnostics.Warn,
            [vim.diagnostic.severity.HINT] = icons.diagnostics.Hint,
            [vim.diagnostic.severity.INFO] = icons.diagnostics.Info,
          },
        },
      }
      -- lspconfig.tsserver.setup {
      -- on_attach = function(_, bufnr)
      --
      -- end
      -- capabilities = capabilities,
      -- }
      -- lspconfig.eslint.setup {
      --   on_attach = function(client, bufnr)
      --     vim.api.nvim_create_autocmd("BufWritePre", {
      --       buffer = bufnr,
      --       command = "EslintFixAll",
      --       -- command = "FormatWriteLock",
      --     })
      --   end,
      -- }

      local servers = { "vuels", "html", "cssls", "jsonls", "bashls", "clangd" }

      for _, server in ipairs(servers) do
        lspconfig[server].setup {
          capabilities = capabilities,
        }
      end

      -- local config = require 'next.config'
      lspconfig.lua_ls.setup {
        capabilities = capabilities,
        settings = {
          Lua = {
            diagnostics = {
              globals = { "vim" },
            },
            workspace = {
              library = {
                [vim.fn.expand "$VIMRUNTIME/lua"] = true,
                [vim.fn.expand "$VIMRUNTIME/lua/vim/lsp"] = true,
                -- [ config.plugins.install_path.."Lazy.nvim/lua" ] = true,
              },
              maxPreload = 100000,
              preloadFileSize = 10000,
            },
          },
        },
      }
      -- lspconfig.rust_analyzer.setup {
      --   -- Server-specific settings. See `:help lspconfig-setup`
      --   settings = {
      --     ["rust-analyzer"] = {},
      --   },
      -- }
    end,
  },

  {
    "Ziphold/tokyonight.nvim",
    lazy = false,
    priority = 1000,
    opts = {},
    config = function()
      require("tokyonight").setup {
        -- your configuration comes here
        -- or leave it empty to use the default settings
        style = "moon",         -- The theme comes in three styles, `storm`, `moon`, a darker variant `night` and `day`
        light_style = "day",    -- The theme is used when the background is set to light
        transparent = true,     -- Enable this to disable setting the background color
        terminal_colors = true, -- Configure the colors used when opening a `:terminal` in [Neovim](https://github.com/neovim/neovim)
        styles = {
          -- Style to be applied to different syntax groups
          -- Value is any valid attr-list value for `:help nvim_set_hl`
          comments = { italic = true },
          keywords = { italic = true },
          functions = {},
          variables = {},
          -- Background styles. Can be "dark", "transparent" or "normal"
          sidebars = "transparent",       -- style for sidebars, see below
          floats = "transparent",         -- style for floating windows
        },
        sidebars = { "qf", "help" },      -- Set a darker background on sidebar-like windows. For example: `["qf", "vista_kind", "terminal", "packer"]`
        day_brightness = 0.3,             -- Adjusts the brightness of the colors of the **Day** style. Number between 0 and 1, from dull to vibrant colors
        hide_inactive_statusline = false, -- Enabling this option, will hide inactive statuslines and replace them with a thin border instead. Should work with the standard **StatusLine** and **LuaLine**.
        dim_inactive = false,             -- dims inactive windows
        lualine_bold = false,             -- When `true`, section headers in the lualine theme will be bold

        --- You can override specific color groups to use other groups or a hex color
        --- function will be called with a ColorScheme table
        ---@param colors ColorScheme
        on_colors = function(colors) end,

        --- You can override specific highlights to use other groups or a hex color
        --- function will be called with a Highlights and ColorScheme table
        ---@param highlights Highlights
        ---@param colors ColorScheme
        on_highlights = function(highlights, colors) end,
      }
    end,
  },
  {
    "Ziphold/bufferline.nvim",
    dependencies = "Ziphold/nvim-web-devicons",
    opts = {},
  },
  {
    "Ziphold/lualine.nvim",
    opts = {},
  },
  {
    "Ziphold/breadcrumbs.nvim",
    dependencies = {
      { "Ziphold/nvim-navic" },
    },
    event = "VeryLazy",
    opts = {},
    config = function()
      require("nvim-navic").setup {
        lsp = {
          auto_attach = true,
        },
      }

      require("breadcrumbs").setup()
    end,
  },

  -- Only load whichkey after all the gui
  {
    "Ziphold/which-key.nvim",
    keys = { "<leader>", "<c-r>", "<c-w>", '"', "'", "`", "c", "v", "g" },
    event = "VeryLazy",
    cmd = "WhichKey",
    opts = {},
  },

  {
    "Ziphold/gitsigns.nvim",
    opts = {
      signs = {
        add = { text = "│" },
        change = { text = "│" },
        delete = { text = "󰍵" },
        topdelete = { text = "‾" },
        changedelete = { text = "~" },
        untracked = { text = "│" },
      },

      on_attach = function(bufnr)
        local gs = package.loaded.gitsigns

        local function map(mode, l, r, opts)
          opts = opts or {}
          opts.buffer = bufnr
          vim.keymap.set(mode, l, r, opts)
        end

        -- Navigation
        map("n", "]c", function()
          if vim.wo.diff then
            return "]c"
          end
          vim.schedule(function()
            gs.next_hunk()
          end)
          return "<Ignore>"
        end, { expr = true })

        map("n", "[c", function()
          if vim.wo.diff then
            return "[c"
          end
          vim.schedule(function()
            gs.prev_hunk()
          end)
          return "<Ignore>"
        end, { expr = true })

        -- Actions
        map("n", "<leader>sh", gs.stage_hunk, { desc = "stage hunk" })
        map("n", "<leader>rh", gs.reset_hunk, { desc = "reset hunk" })
        map("v", "<leader>sh", function()
          gs.stage_hunk { vim.fn.line ".", vim.fn.line "v" }
        end, { desc = "stage hunk" })
        map("v", "<leader>rh", function()
          gs.reset_hunk { vim.fn.line ".", vim.fn.line "v" }
        end, { desc = "reset hunk" })
        map("n", "<leader>sb", gs.stage_buffer, { desc = "stage buffer" })
        map("n", "<leader>us", gs.undo_stage_hunk, { desc = "undo stage hunk" })
        map("n", "<leader>gR", gs.reset_buffer, { desc = "reset buffer" })
        map("n", "<leader>gp", gs.preview_hunk, { desc = "preview hunk" })
        map("n", "<leader>gb", function()
          gs.blame_line { full = true }
        end, { desc = "git blame" })
        -- map('n', '<leader>tb', gs.toggle_current_line_blame, {desc = 'git blame current lint'})
        map("n", "<leader>gd", gs.diffthis, { desc = "git diff this" })
        map("n", "<leader>gD", function()
          gs.diffthis "~"
        end, { desc = "git diff this ~" })
        map("n", "<leader>td", gs.toggle_deleted, { desc = "toggle_deleted" })

        -- Text object
        map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>")
      end,
    },
  },

  {
    "Ziphold/git-conflict.nvim",
    dev = true,
    config = function()
      require("git-conflict").setup {
        default_mappings = true,    -- disable buffer local mapping created by this plugin
        disable_diagnostics = true, -- This will disable the diagnostics in a buffer whilst it is conflicted
        highlights = {
          incoming = "DiffText",
          current = "DiffAdd",
        },
      }
    end,
  },
  {
    "Ziphold/alpha-nvim",
    dependencies = { "Ziphold/nvim-web-devicons" },
    config = function()
      require("alpha").setup(require("alpha.themes.startify").config)
    end,
  },
  --{
  --   "Ziphold/coc.nvim",
  --   config = function()
  --     -- Some servers have issues with backup files, see #649
  --     vim.opt.backup = false
  --     vim.opt.writebackup = false
  --
  --     -- Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
  --     -- delays and poor user experience
  --     vim.opt.updatetime = 300
  --
  --     -- Always show the signcolumn, otherwise it would shift the text each time
  --     -- diagnostics appeared/became resolved
  --     vim.opt.signcolumn = "yes"
  --
  --     local keyset = vim.keymap.set
  --     -- Autocomplete
  --     function _G.check_back_space()
  --       local col = vim.fn.col('.') - 1
  --       return col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') ~= nil
  --     end
  --
  --     -- Use Tab for trigger completion with characters ahead and navigate
  --     -- NOTE: There's always a completion item selected by default, you may want to enable
  --     -- no select by setting `"suggest.noselect": true` in your configuration file
  --     -- NOTE: Use command ':verbose imap <tab>' to make sure Tab is not mapped by
  --     -- other plugins before putting this into your config
  --     local opts = { silent = true, noremap = true, expr = true, replace_keycodes = false }
  --     keyset("i", "<TAB>", 'coc#pum#visible() ? coc#pum#next(1) : v:lua.check_back_space() ? "<TAB>" : coc#refresh()',
  --       opts)
  --     keyset("i", "<S-TAB>", [[coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"]], opts)
  --
  --     -- Make <CR> to accept selected completion item or notify coc.nvim to format
  --     -- <C-g>u breaks current undo, please make your own choice
  --     keyset("i", "<cr>", [[coc#pum#visible() ? coc#pum#confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"]], opts)
  --
  --     -- Use <c-j> to trigger snippets
  --     keyset("i", "<c-j>", "<Plug>(coc-snippets-expand-jump)")
  --     -- Use <c-space> to trigger completion
  --     keyset("i", "<c-space>", "coc#refresh()", { silent = true, expr = true })
  --
  --     -- Use `[g` and `]g` to navigate diagnostics
  --     -- Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
  --     keyset("n", "[g", "<Plug>(coc-diagnostic-prev)", { silent = true })
  --     keyset("n", "]g", "<Plug>(coc-diagnostic-next)", { silent = true })
  --
  --     -- GoTo code navigation
  --     keyset("n", "gd", "<Plug>(coc-definition)", { silent = true })
  --     keyset("n", "gy", "<Plug>(coc-type-definition)", { silent = true })
  --     keyset("n", "gi", "<Plug>(coc-implementation)", { silent = true })
  --     keyset("n", "gr", "<Plug>(coc-references)", { silent = true })
  --
  --
  --     -- Use K to show documentation in preview window
  --     function _G.show_docs()
  --       local cw = vim.fn.expand('<cword>')
  --       if vim.fn.index({ 'vim', 'help' }, vim.bo.filetype) >= 0 then
  --         vim.api.nvim_command('h ' .. cw)
  --       elseif vim.api.nvim_eval('coc#rpc#ready()') then
  --         vim.fn.CocActionAsync('doHover')
  --       else
  --         vim.api.nvim_command('!' .. vim.o.keywordprg .. ' ' .. cw)
  --       end
  --     end
  --
  --     keyset("n", "K", '<CMD>lua _G.show_docs()<CR>', { silent = true })
  --
  --
  --     -- Highlight the symbol and its references on a CursorHold event(cursor is idle)
  --     vim.api.nvim_create_augroup("CocGroup", {})
  --     vim.api.nvim_create_autocmd("CursorHold", {
  --       group = "CocGroup",
  --       command = "silent call CocActionAsync('highlight')",
  --       desc = "Highlight symbol under cursor on CursorHold"
  --     })
  --
  --
  --     -- Symbol renaming
  --     keyset("n", "<leader>rn", "<Plug>(coc-rename)", { silent = true })
  --
  --
  --     -- Formatting selected code
  --     keyset("x", "<leader>f", "<Plug>(coc-format-selected)", { silent = true })
  --     keyset("n", "<leader>f", "<Plug>(coc-format-selected)", { silent = true })
  --
  --
  --     -- Setup formatexpr specified filetype(s)
  --     vim.api.nvim_create_autocmd("FileType", {
  --       group = "CocGroup",
  --       pattern = "typescript,json",
  --       command = "setl formatexpr=CocAction('formatSelected')",
  --       desc = "Setup formatexpr specified filetype(s)."
  --     })
  --
  --     -- Update signature help on jump placeholder
  --     vim.api.nvim_create_autocmd("User", {
  --       group = "CocGroup",
  --       pattern = "CocJumpPlaceholder",
  --       command = "call CocActionAsync('showSignatureHelp')",
  --       desc = "Update signature help on jump placeholder"
  --     })
  --
  --     -- Apply codeAction to the selected region
  --     -- Example: `<leader>aap` for current paragraph
  --     keyset("x", "<leader>a", "<Plug>(coc-codeaction-selected)", opts)
  --     keyset("n", "<leader>a", "<Plug>(coc-codeaction-selected)", opts)
  --
  --     -- Remap keys for apply code actions at the cursor position.
  --     keyset("n", "<leader>ac", "<Plug>(coc-codeaction-cursor)", opts)
  --     -- Remap keys for apply source code actions for current file.
  --     keyset("n", "<leader>as", "<Plug>(coc-codeaction-source)", opts)
  --     -- Apply the most preferred quickfix action on the current line.
  --     keyset("n", "<leader>qf", "<Plug>(coc-fix-current)", opts)
  --
  --     -- Remap keys for apply refactor code actions.
  --     keyset("n", "<leader>re", "<Plug>(coc-codeaction-refactor)", { silent = true })
  --     keyset("x", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
  --     keyset("n", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
  --
  --     -- Run the Code Lens actions on the current line
  --     keyset("n", "<leader>cl", "<Plug>(coc-codelens-action)", opts)
  --
  --
  --     -- Map function and class text objects
  --     -- NOTE: Requires 'textDocument.documentSymbol' support from the language server
  --     keyset("x", "if", "<Plug>(coc-funcobj-i)", opts)
  --     keyset("o", "if", "<Plug>(coc-funcobj-i)", opts)
  --     keyset("x", "af", "<Plug>(coc-funcobj-a)", opts)
  --     keyset("o", "af", "<Plug>(coc-funcobj-a)", opts)
  --     keyset("x", "ic", "<Plug>(coc-classobj-i)", opts)
  --     keyset("o", "ic", "<Plug>(coc-classobj-i)", opts)
  --     keyset("x", "ac", "<Plug>(coc-classobj-a)", opts)
  --     keyset("o", "ac", "<Plug>(coc-classobj-a)", opts)
  --
  --
  --     -- Remap <C-f> and <C-b> to scroll float windows/popups
  --     ---@diagnostic disable-next-line: redefined-local
  --     local opts = { silent = true, nowait = true, expr = true }
  --     keyset("n", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
  --     keyset("n", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
  --     keyset("i", "<C-f>",
  --       'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(1)<cr>" : "<Right>"', opts)
  --     keyset("i", "<C-b>",
  --       'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(0)<cr>" : "<Left>"', opts)
  --     keyset("v", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
  --     keyset("v", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
  --
  --
  --     -- Use CTRL-S for selections ranges
  --     -- Requires 'textDocument/selectionRange' support of language server
  --     keyset("n", "<C-s>", "<Plug>(coc-range-select)", { silent = true })
  --     keyset("x", "<C-s>", "<Plug>(coc-range-select)", { silent = true })
  --
  --
  --     -- Add `:Format` command to format current buffer
  --     vim.api.nvim_create_user_command("Format", "call CocAction('format')", {})
  --
  --     -- " Add `:Fold` command to fold current buffer
  --     vim.api.nvim_create_user_command("Fold", "call CocAction('fold', <f-args>)", { nargs = '?' })
  --
  --     -- Add `:OR` command for organize imports of the current buffer
  --     vim.api.nvim_create_user_command("OR", "call CocActionAsync('runCommand', 'editor.action.organizeImport')", {})
  --
  --     -- Add (Neo)Vim's native statusline support
  --     -- NOTE: Please see `:h coc-status` for integrations with external plugins that
  --     -- provide custom statusline: lightline.vim, vim-airline
  --     vim.opt.statusline:prepend("%{coc#status()}%{get(b:,'coc_current_function','')}")
  --
  --     -- Mappings for CoCList
  --     -- code actions and coc stuff
  --     ---@diagnostic disable-next-line: redefined-local
  --     local opts = { silent = true, nowait = true }
  --     -- Show all diagnostics
  --     keyset("n", "<space>a", ":<C-u>CocList diagnostics<cr>", opts)
  --     -- Manage extensions
  --     keyset("n", "<space>e", ":<C-u>CocList extensions<cr>", opts)
  --     -- Show commands
  --     keyset("n", "<space>c", ":<C-u>CocList commands<cr>", opts)
  --     -- Find symbol of current document
  --     keyset("n", "<space>o", ":<C-u>CocList outline<cr>", opts)
  --     -- Search workspace symbols
  --     keyset("n", "<space>s", ":<C-u>CocList -I symbols<cr>", opts)
  --     -- Do default action for next item
  --     keyset("n", "<space>j", ":<C-u>CocNext<cr>", opts)
  --     -- Do default action for previous item
  --     keyset("n", "<space>k", ":<C-u>CocPrev<cr>", opts)
  --     -- Resume latest coc list
  --     keyset("n", "<space>p", ":<C-u>CocListResume<cr>", opts)
  --   end
  -- },
  {
    "Ziphold/nvim-dap-ui",
    opts = {},
    init = function()
      local dap, dapui = require "dap", require "dapui"
      dap.listeners.before.attach.dapui_config = function()
        dapui.open()
      end
      dap.listeners.before.launch.dapui_config = function()
        dapui.open()
      end
      dap.listeners.before.event_terminated.dapui_config = function()
        dapui.close()
      end
      dap.listeners.before.event_exited.dapui_config = function()
        dapui.close()
      end
      dap.adapters["pwa-node"] = {
        type = "server",
        host = "localhost",
        port = "${port}",
        executable = {
          command = "node",
          -- 💀 Make sure to update this path to point to your installation
          args = { vim.fn.stdpath "config" .. "/js-debug/src/dapDebugServer.js", "${port}" },
        },
      }
      dap.configurations.javascript = {
        {
          type = "pwa-node",
          request = "launch",
          name = "Launch file",
          program = "${file}",
          cwd = "${workspaceFolder}",
        },
      }

      local extension_path = vim.env.HOME .. '/.vscode/extensions/vadimcn.vscode-lldb-1.10.0/'
      local codelldb_path = extension_path .. 'adapter/codelldb'
      local liblldb_path = extension_path .. 'lldb/lib/liblldb'
      local this_os = vim.uv.os_uname().sysname;

      -- The path is different on Windows
      if this_os:find "Windows" then
        codelldb_path = extension_path .. "adapter\\codelldb.exe"
        liblldb_path = extension_path .. "lldb\\bin\\liblldb.dll"
      else
        -- The liblldb extension is .so for Linux and .dylib for MacOS
        liblldb_path = liblldb_path .. (this_os == "Linux" and ".so" or ".dylib")
      end
      dap.adapters.codelldb = {
        type = 'server',
        port = "${port}",
        executable = {
          -- CHANGE THIS to your path!
          command = codelldb_path,
          args = { "--port", "${port}" },

          -- On windows you may have to uncomment this:
          -- detached = false,
        }
      }

      dap.configurations.cpp = {
        {
          name = "Launch file",
          type = "codelldb",
          request = "launch",
          program = function()
            
            return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file')
          end,
          cwd = '${workspaceFolder}',
          stopOnEntry = false,
        },
      }
    end,
    dependencies = {
      "Ziphold/nvim-dap",
      "Ziphold/nvim-nio",
      {
        "Ziphold/neodev.nvim",
        config = function()
          require("neodev").setup {
            library = { plugins = { "nvim-dap-ui" }, types = true },
          }
        end,
      },
      { "Ziphold/nvim-dap-virtual-text", opts = {} },
    },
  },
  -- {
  --   "Ziphold/tmux-navigator.nvim",
  --   opts = { enable = true }
  -- },
  {
    "Ziphold/indent-blankline.nvim",
    main = "ibl",
    config = function()
      local highlight = {
        "RainbowRed",
        "RainbowYellow",
        "RainbowBlue",
        "RainbowOrange",
        "RainbowGreen",
        "RainbowViolet",
        "RainbowCyan",
      }

      local hooks = require "ibl.hooks"
      -- create the highlight groups in the highlight setup hook, so they are reset
      -- every time the colorscheme changes
      hooks.register(hooks.type.HIGHLIGHT_SETUP, function()
        vim.api.nvim_set_hl(0, "RainbowRed", { fg = "#E06C75" })
        vim.api.nvim_set_hl(0, "RainbowYellow", { fg = "#E5C07B" })
        vim.api.nvim_set_hl(0, "RainbowBlue", { fg = "#61AFEF" })
        vim.api.nvim_set_hl(0, "RainbowOrange", { fg = "#D19A66" })
        vim.api.nvim_set_hl(0, "RainbowGreen", { fg = "#98C379" })
        vim.api.nvim_set_hl(0, "RainbowViolet", { fg = "#C678DD" })
        vim.api.nvim_set_hl(0, "RainbowCyan", { fg = "#56B6C2" })
      end)

      require("ibl").setup { indent = { highlight = highlight } }
    end
  },
  {
    "mirrors_s1n7ax/nvim-search-and-replace",
    config = function()
      require("nvim-search-and-replace").setup()
    end,
  },
  {
    "Ziphold/bigfile.nvim",
    opts = {},
  },
  {
    "Ziphold/nvim-colorizer.lua",
    opts = {},
  },
  {},
  {
    "Ziphold/nvim-notify",
    opts = {
      stages = "static",
      timeout = 3000,
      render = "wrapped-compact",
    },
  },
  {
    "Ziphold/symbols-outline.nvim",
    opts = {
      fold_markers = { "", "" },
      symbols = {
        File = { icon = "", hl = "@text.uri" },
        Module = { icon = "", hl = "@namespace" },
        Namespace = { icon = "", hl = "@namespace" },
        Package = { icon = "", hl = "@namespace" },
        Class = { icon = "𝓒", hl = "@type" },
        Method = { icon = "ƒ", hl = "@method" },
        Property = { icon = "", hl = "@method" },
        Field = { icon = "", hl = "@field" },
        Constructor = { icon = "", hl = "@constructor" },
        Enum = { icon = "ℰ", hl = "@type" },
        Interface = { icon = "ﰮ", hl = "@type" },
        Function = { icon = "", hl = "@function" },
        Variable = { icon = "", hl = "@constant" },
        Constant = { icon = "", hl = "@constant" },
        String = { icon = "𝓐", hl = "@string" },
        Number = { icon = "#", hl = "@number" },
        Boolean = { icon = "⊨", hl = "@boolean" },
        Array = { icon = "", hl = "@constant" },
        Object = { icon = "⦿", hl = "@type" },
        Key = { icon = "🔐", hl = "@type" },
        Null = { icon = "NULL", hl = "@type" },
        EnumMember = { icon = "", hl = "@field" },
        Struct = { icon = "𝓢", hl = "@type" },
        Event = { icon = "🗲", hl = "@type" },
        Operator = { icon = "+", hl = "@operator" },
        TypeParameter = { icon = "𝙏", hl = "@parameter" },
        Component = { icon = "", hl = "@function" },
        Fragment = { icon = "", hl = "@constant" },
      },
    },
    dependencies = { "Ziphold/nvim-web-devicons" },
  },
  {
    "mirrorsdemo/lspsaga.nvim",
    lazy = false,
    opts = {},
  },
  {
    "Ziphold/refactoring.nvim",
    opts = {},
    dependencies = { "Ziphold/plenary.nvim", "Ziphold/nvim-treesitter" },
  },
  -- lazy.nvim
  {
    "Ziphold/noice.nvim",
    event = "VeryLazy",
    opts = {
      health = {
        checker = false,
      },
      -- routes = {
      --   filter = { event = "msg_show", kind = "search_count" },
      --   opts = { skip = true },
      -- },
      redirect = {
        -- view = "popup",
        filter = { event = "msg_show" },
      },
      lsp = {
        -- override markdown rendering so that **cmp** and other plugins use **Treesitter**
        override = {
          ["vim.lsp.util.convert_input_to_markdown_lines"] = true,
          ["vim.lsp.util.stylize_markdown"] = true,
          ["cmp.entry.get_documentation"] = true, -- requires hrsh7th/nvim-cmp
        },
      },
      -- you can enable a preset for easier configuration
      presets = {
        bottom_search = true,         -- use a classic bottom cmdline for search
        command_palette = true,       -- position the cmdline and popupmenu together
        long_message_to_split = true, -- long messages will be sent to a split
        inc_rename = true,            -- enables an input dialog for inc-rename.nvim
        lsp_doc_border = false,       -- add a border to hover docs and signature help
      },
    },                                -- add any options here
    dependencies = {
      -- if you lazy-load any plugin below, make sure to add proper `module="..."` entries
      "Ziphold/nui.nvim",
      -- OPTIONAL:
      --   `nvim-notify` is only needed, if you want to use the notification view.
      --
      --   If not available, we use `mini` as the fallback
      "Ziphold/nvim-notify",
    },
  },
  {
    "Ziphold/inc-rename.nvim",
    opts = {
      post_hook = function()
        vim.cmd "wa"
      end,
    },
  },
  {
    "Ziphold/none-ls.nvim",
    opts = {},
    config = function(_, opts)
      local null_ls = require "null-ls"

      null_ls.setup {
        sources = {
          -- null_ls.builtins.formatting.clang_format,
          -- null_ls.builtins.formatting.stylua,
          -- null_ls.builtins.diagnostics.eslint,
          -- null_ls.builtins.completion.spell,
          -- null_ls.builtins.completion.luasnip,
          -- null_ls.builtins.formatting.prettier.with {
          --   extra_filetypes = { "toml" },
          -- },
          -- null_ls.builtins.code_actions.gitsigns.with {
          --   config = {
          --     filter_actions = function(title)
          --       return title:lower():match "blame" == nil -- filter out blame actions
          --     end,
          --   },
          -- },
        },
      }
    end,
  },

  {
    "Ziphold/conform.nvim",
    opts = {
      formatters_by_ft = {
        lua = { "stylua" },
        -- Conform will run multiple formatters sequentially
        -- python = { "isort", "black" },
        -- Use a sub-list to run only the first available formatter
        jsonc = { { "prettierd", "prettier" } },
        -- javascript = { { "prettierd", "prettier" } },
      },
    },
  },

  {
    'Ziphold/nvim-lint',
    opts = {},
    config = function()
      -- require('lint').linters_by_ft = {
      --   typescript = 'eslint'
      -- }
      --
      -- vim.cmd [[ au BufWritePost * lua require('lint').try_lint() ]]
      vim.api.nvim_create_autocmd({ "InsertLeave", "VimEnter" }, {
        callback = function()
          -- try_lint without arguments runs the linters defined in `linters_by_ft`
          -- for the current filetype
          require("lint").try_lint()

          -- You can call `try_lint` with a linter name or a list of names to always
          -- run specific linters, independent of the `linters_by_ft` configuration
          -- require("lint").try_lint("cspell")
        end,
      })
    end
  },
  -- {
  --   'Ziphold/formatter.nvim',
  --   opts = {},
  --   event = 'VeryLazy',
  --   config = function()
  --     filetype = {
  --       -- Formatter configurations for filetype "lua" go here
  --       -- and will be executed in order
  --       lua = {
  --         -- "formatter.filetypes.lua" defines default configurations for the
  --         -- "lua" filetype
  --         require("formatter.filetypes.lua").stylua,
  --       },
  --       javascript = {
  --         require 'formatter.filetypes.javascript'.prettiereslint
  --       },
  --       javascriptreact = {
  --         require 'formatter.filetypes.javascriptreact'.prettiereslint
  --       },
  --       typescript = {
  --         require('formatter.filetypes.typescript').prettiereslint
  --       },
  --       typescriptreact = {
  --         require('formatter.filetypes.typescriptreact').prettiereslint
  --       },
  --       ["*"] = {
  --         -- "formatter.filetypes.any" defines default configurations for any
  --         -- filetype
  --         require("formatter.filetypes.any").remove_trailing_whitespace
  --       }
  --
  --     }
  --   end
  -- }
  {
    "Ziphold/nvim-spectre",
    opts = {

    }
  },
  -- {
  --   'Ziphold/typescript.nvim',
  --   opts = {}
  -- },
  {
    'Ziphold/typescript-tools.nvim',
    opts = {
      settings = {
        expose_as_code_action = 'all',

      }
    },
    dependencies = { "Ziphold/plenary.nvim", "Ziphold/nvim-lspconfig" },
  },
  {
    "Ziphold/rust.vim",
    ft = "rust",
    init = function()
      vim.g.rustfmt_autosave = 1
    end
  },
  {
    "Ziphold/rustaceanvim",
    version = '^4', -- Recommended
    ft = { 'rust' },
    dependencies = { 'Ziphold/nvim-lspconfig' },
    init = function()
      -- Update this path
      local extension_path = vim.env.HOME .. '/.vscode/extensions/vadimcn.vscode-lldb-1.10.0/'
      local codelldb_path = extension_path .. 'adapter/codelldb'
      local liblldb_path = extension_path .. 'lldb/lib/liblldb'
      local this_os = vim.uv.os_uname().sysname;

      -- The path is different on Windows
      if this_os:find "Windows" then
        codelldb_path = extension_path .. "adapter\\codelldb.exe"
        liblldb_path = extension_path .. "lldb\\bin\\liblldb.dll"
      else
        -- The liblldb extension is .so for Linux and .dylib for MacOS
        liblldb_path = liblldb_path .. (this_os == "Linux" and ".so" or ".dylib")
      end


      local cfg = require('rustaceanvim.config')
      vim.g.rustaceanvim = {
        -- Plugin configuration
        tools = {
        },
        -- LSP configuration
        server = {
          on_attach = function(client, bufnr)
            -- you can also put keymaps in here
          end,
          default_settings = {
            -- rust-analyzer language server configuration
            ['rust-analyzer'] = {
              cargo = {
                allFeatures = true,
              }
            },
          },
        },
        -- DAP configuration
        dap = {
          adapter = cfg.get_codelldb_adapter(codelldb_path, liblldb_path)
        },
      }
    end
  },
  {
    'Ziphold/crates.nvim',
    tag = 'stable',
    ft = { "rust", "toml" },
    opts = {}
  }
}

return M
